package fec

import (
"github.com/lucas-clemente/quic-go/internal/protocol"
)

type FECScheduler interface {
	//GetNextFECPayload() *wire.RepairSymbol
	// called to indicate that a RepairSymbol for a particular FEC Group has been sent and should thus be replaced by a new one in the scheduler
	SentFECGroup(protocol.FECGroup)
	GetNextFECGroupNumber() protocol.FECGroup
	GetNextFECGroup()	*FECGroup
	GetNextFECGroupOffset() byte
}

type RoundRobinScheduler struct {
	fecGroups						  []*FECGroup
	maxSize								uint
	size									uint
	offset 								uint
	nextFECGroupNumber 		protocol.FECGroup
	fecGroupNumberToIndex	map[protocol.FECGroup]uint
	version 							protocol.VersionNumber
}

var _ FECScheduler = &RoundRobinScheduler{}

func NewRoundRobinScheduler(maxSize uint, version protocol.VersionNumber) *RoundRobinScheduler {
	return &RoundRobinScheduler{
		fecGroups:             make([]*FECGroup, maxSize),
		maxSize:               maxSize,
		size:                  0,
		offset: 							 0,
		nextFECGroupNumber: 	 0,
		fecGroupNumberToIndex: make(map[protocol.FECGroup]uint),
		version:							 version,
	}
}



func (s *RoundRobinScheduler) SentFECGroup(group protocol.FECGroup) {
	index, ok := s.fecGroupNumberToIndex[group]
	if ok {
		delete(s.fecGroupNumberToIndex, group)
		// fill the hole created
		s.putNewFECGroupAtIndex(index)
	}
}

// post: the FECGroup of the returned FECGroupNumber can be added at least one more packet
func (s *RoundRobinScheduler) GetNextFECGroupNumber() protocol.FECGroup {
	if s.size < s.maxSize {
		return s.nextFECGroupNumber
	}
	return s.fecGroups[s.offset].FECGroupNumber
}

// post: the returned RepairSymbol can be added at least one more packet
func (s *RoundRobinScheduler) GetNextFECGroup() *FECGroup {
	if s.size < s.maxSize && s.offset == s.size {
		s.putNewFECGroupAtIndex(s.size)
		s.size++
		retVal := s.fecGroups[s.offset]
		s.offset = (s.offset + 1) % s.maxSize
		return retVal
	} else {
		retVal := s.fecGroups[s.offset]
		s.offset = (s.offset + 1) % s.maxSize
		return retVal
	}
}

func (s *RoundRobinScheduler) GetNextFECGroupOffset() byte {
	if s.size < s.maxSize && s.offset == s.size {
		return 0
	}
	return byte(s.fecGroups[s.offset].CurrentNumberOfPackets())
}

func (s *RoundRobinScheduler) getNextFECGroupNumberAndThenIncrementIt() protocol.FECGroup {
	s.nextFECGroupNumber++
	return s.nextFECGroupNumber -1
}

func (s *RoundRobinScheduler) putNewFECGroupAtIndex(index uint) {
	fecGroupNumber := s.getNextFECGroupNumberAndThenIncrementIt()
	s.fecGroups[index] = NewFECGroup(fecGroupNumber, s.version)
	s.fecGroupNumberToIndex[fecGroupNumber] = index
}